package com.syqc.videos

import android.annotation.SuppressLint
import android.content.Context
import com.syqc.comlib.UserConstant
import com.syqc.comlib.utils.AppContext
import com.syqc.comlib.utils.GsonUtil
import com.syqc.entity.VideoHost
import com.syqc.entity.VideoState
import com.syqc.monitor.R
import com.syqc.net.ServiceHelper
import com.syqc.utils.ToolsUtil
import com.syqc.utils.UrlUtil
import com.syqc.utils.VideoHostUtil
import com.syqc.videos.players.AudioCallBack
import com.syqc.videos.players.AudioPlayer
import com.syqc.videos.videomanager.PlayerManager
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.subjects.PublishSubject
import java.net.URLEncoder
import java.util.UUID
import kotlin.concurrent.thread

object TalkbackUtil {
    private var talkHelper: TalkHelper? = null
    private var audioPlayer: AudioPlayer? = null
    private var uuid: String = ""
    private var subscribe: Disposable? = null
    private var stateSubscribe: Disposable? = null
    private lateinit var videoHost: VideoHost

    //是否是地图界面
    private var isMap = true


    //对讲状态
    private val _status = PublishSubject.create<TalkStatus>()
    val status = _status.hide()

    var toast = ""

    //上传失败
    private val _upload = PublishSubject.create<Boolean>()
    val upload = _upload.hide()

    //声音图片
    private val _image = PublishSubject.create<Int>()
    val image = _image.hide()

    //对讲状态
    private val _statusMap = PublishSubject.create<TalkStatus>()
    val statusMap = _statusMap.hide()


    //上传失败
    private val _uploadMap = PublishSubject.create<Boolean>()
    val uploadMap = _uploadMap.hide()

    //声音图片
    private val _imageMap = PublishSubject.create<Int>()
    val imageMap = _imageMap.hide()

    //提示
    private val _toastLive = PublishSubject.create<String>()
    val toastLive = _toastLive.hide()



    @SuppressLint("CheckResult")
    private fun initTalk(context: Context) {
        userIdEncode= URLEncoder.encode(UserConstant.current_userId.replace(".", "_"), "utf-8")
        user = "$userIdEncode*${UserConstant.current_pwd_md5}"
        uuid = UUID.randomUUID().toString()
        talkHelper = talkHelper ?: TalkHelper().apply {
            setSpeakerphoneOn(context)
            talkObserver().observeOn(AndroidSchedulers.mainThread()).subscribe {
                closeTalk()
                if (isMap) {
                    _uploadMap.onNext(true)
                } else {
                    _upload.onNext(true)
                }
            }
            talkImgObserver().observeOn(AndroidSchedulers.mainThread()).subscribe {
                if (it in 1..9) {
                    if (isMap) {
                        _imageMap.onNext(TalkHelper.voiceImg[it])
                    } else {
                        _image.onNext(TalkHelper.voiceImg[it])
                    }
                }
            }
        }
        audioPlayer = audioPlayer ?: AudioPlayer(context)

    }

    private fun initAudio(carId: String, channel: String) {
        audioPlayer?.run {
            setUp(getPlayParams(carId, channel), false, "video")
            setAudioCallBack(callback)
            startPlayLogic()
        }

        if (isMap) {
            _statusMap.onNext(TalkStatus.OPEN)
        } else {
            _status.onNext(TalkStatus.OPEN)
        }
    }


    private val callback = object : AudioCallBack {

        override fun finishTalk() {
            closeAudio(uuid)
            if (isMap) {
                _statusMap.onNext(TalkStatus.CLOSE)
            } else
                _status.onNext(TalkStatus.CLOSE)
        }

        override fun success() {
            talkHelper?.start("${VideoHostUtil.getHost(videoHost)}/microphone.$uuid")
            if (isMap) {
                _statusMap.onNext(TalkStatus.SUCCESS)
            } else
                _status.onNext(TalkStatus.SUCCESS)
        }

        override fun failure() {
            getAudioState(uuid)
            closeAudio(uuid)
        }
    }

    private fun closeAudio() {
        talkHelper?.stopRecord()
        audioPlayer?.releaseVideos()
        audioPlayer?.release()
        audioPlayer = null
    }

    private var userIdEncode:String = URLEncoder.encode(UserConstant.current_userId.replace(".", "_"), "utf-8")

    private var user = "$userIdEncode*${UserConstant.current_pwd_md5}"

    /** 获取播放视频参数 */
    private fun getPlayParams(carId: String, channel: String): String {
        return "${VideoHostUtil.getHost(videoHost)}/httpflv.talk_open.$uuid.$user.$carId.$channel"
    }

    /**
     * 查询对讲状态
     *
     * @param uuid
     */
    private fun getAudioState(uuid: String) {
        val url = "${VideoHostUtil.getHost(videoHost)}/httpflv.state.$uuid"
        stateSubscribe?.dispose()
        stateSubscribe = ServiceHelper.getRepository().getVideoState(url)
            .subscribe({
                if (it.isNullOrEmpty()) {
                    toast = UrlUtil.getToastMap()["88"] ?: ""
                    if (isMap) {
                        _statusMap.onNext(TalkStatus.FAILURE)
                    } else {
                        _status.onNext(TalkStatus.FAILURE)
                    }
                    return@subscribe
                }
                //兼容部分没有返回｝的情况
                val value = if (!it.endsWith("}")) {
                    "$it}"
                } else {
                    it
                }
                val result = GsonUtil.formObject<VideoState?>(value)
                toast = if (result == null) {
                    UrlUtil.getToastMap()["88"] ?: ""
                } else {
                    UrlUtil.getToastMap()[result.state] ?: ""
                }
                if (isMap) {
                    _statusMap.onNext(TalkStatus.FAILURE)
                } else {
                    _status.onNext(TalkStatus.FAILURE)
                }
            }, {
                this.toast = AppContext.getDescById(R.string.toast_audio_faile)
                if (isMap) {
                    _statusMap.onNext(TalkStatus.FAILURE)
                } else {
                    _status.onNext(TalkStatus.FAILURE)
                }
            })
    }

    /**
     * 关闭对讲
     *
     * @param uuid
     */
    fun closeAudio(uuid: String) {
        val url = "${VideoHostUtil.getHost(videoHost)}/httpflv.talk_close.$uuid"
        subscribe?.dispose()
        subscribe = ServiceHelper.getRepository().getVideoState(url)
            .subscribe({
                closeAudio()
            }, {
                closeAudio()
            })
    }

    ///////////////////////////////////////

    fun openTalk(context: Context, carId: String, channel: String, isMap: Boolean = false) {
        if (carId.isEmpty()) return
        videoHost = VideoHostUtil.getVideoHost(carId)

        when (videoHost.isClient) {
            null -> {
                thread {
                    val isClient = ToolsUtil.isReachableByTcp(videoHost.ip, videoHost.port)
                    videoHost.isClient = isClient
                    VideoHostUtil.changeHost(videoHost.index, isClient)
                }
                Thread.sleep(1000)
                if (videoHost.isClient==true) {
                    open(isMap, context, carId, channel)
                } else {
                    val toast =
                        VideoHostUtil.getHost(videoHost) + "\n" + AppContext.getDescById(R.string.toast_port_faile)
                    _toastLive.onNext(toast)
                }
            }

            false -> {
                val toast =
                    VideoHostUtil.getHost(videoHost) + "\n" + AppContext.getDescById(R.string.toast_port_faile)
                _toastLive.onNext(toast)
            }

            else -> {
                open(isMap, context, carId, channel)
            }
        }
    }

    private fun open(
        isMap: Boolean,
        context: Context,
        carId: String,
        channel: String
    ) {
        this.isMap = isMap
        initTalk(context)
        initAudio(carId, channel)
    }

    fun closeTalk() {
        if (!::videoHost.isInitialized) return
        closeAudio(uuid)
        if (isMap) {
            _statusMap.onNext(TalkStatus.CLOSE)
        } else {
            _status.onNext(TalkStatus.CLOSE)
        }
    }

    fun destroy() {
        if (!::videoHost.isInitialized) return
        closeTalk()
        talkHelper?.destroy()
        talkHelper = null
        subscribe?.dispose()
        stateSubscribe?.dispose()
    }

    fun getPlayer() = audioPlayer

    fun clear(){
        audioPlayer?.getKey()?.let { PlayerManager.clearAllNorAudio(it) }
    }
}

enum class TalkStatus {
    CLOSE, OPEN, SUCCESS, FAILURE
}